﻿/*========================== 
 * @author 郑金泉
 * @desc 方法请求参数类
 * ========================= */
using System;
using System.Collections.Generic;
using System.Text;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Obsidian.Utils;
using Obsidian.Edm;

namespace Obsidian.Action
{
    public class ActReqParam
    {
        private string _name;
        private string[] _fields;
        private Dictionary<string, int> _dictFieldIndex = new Dictionary<string, int>();
        private List<object[]> _values = new List<object[]>();


        internal ActReqParam(string name, string[] fields)
        {
            this._name = name;
            this._fields = fields;

            int i = 0;
            foreach (string f in this._fields)
            {
                this._dictFieldIndex[f] = i;
                i++;
            }
        }

        internal ActReqParam(JObject jo)
        {
            try { this._name = Convert.ToString(((JValue)jo["n"]).Value); }
            catch { }
            this._fields = Convert.ToString(((JValue)jo["f"]).Value).Split(',');

            int i = 0;
            foreach (string f in this._fields)
            {
                this._dictFieldIndex[f] = i;
                i++;
            }

            JArray jArray = (JArray)jo["v"];
            foreach (JToken jToken in jArray)
            {
                JArray ja = (JArray)jToken;
                object[] arr = new object[ja.Count];
                int j = 0;
                foreach (JToken jt in ja)
                {
                    arr[j] = ((JValue)jt).Value;
                    j++;
                }
                this._values.Add(arr);
            }
        }

        public string Name
        {
            get { return this._name; }
        }

        public string[] Fields
        {
            get { return this._fields; }
        }

        public int Count
        {
            get { return this._values.Count; }
        }

        public object Get(int index, string fieldName)
        {
            if (index < 0 || index > this._values.Count - 1)
                throw new Exception("index超出范围");
            int colIndex;
            if (!this._dictFieldIndex.TryGetValue(fieldName, out colIndex))
                throw new Exception(String.Format("字段{0}不存在", fieldName));
            object[] arr = this._values[index];
            if (colIndex > arr.Length - 1)
                return null;
            return arr[colIndex];
        }

        public object FirstValue()
        {
            if (this._values.Count == 0)
                return null;
            object[] arr = this._values[0];
            if (arr.Length == 0)
                return null;
            return arr[0];
        }

        public T ToModel<T>(int index) where T : IModel, new()
        {
            if (index < 0)
                throw new Exception("index不能小于0");
            if (index > this._values.Count - 1)
                throw new Exception("index超出范围");

            object[] vals = this._values[index];
            int valsLen = vals.Length;
            T m = new T();
            int len = Math.Min(valsLen, this._fields.Length);
            for (int i = 0; i < len; i++)
            {
                string alias = this._fields[i];
                IModelField field = m.GetFieldByAlias(alias);
                if (field == null)
                    continue;
                field.TrySet(vals[i]);
            }
            return m;
        }

        public T FirstToModel<T>() where T : IModel, new()
        {
            return ToModel<T>(0);
        }

        public List<T> ToModelList<T>() where T : IModel, new()
        {
            List<T> list = new List<T>();
            foreach (object[] vals in this._values)
            {
                int valsLen = vals.Length;
                T m = new T();
                int len = Math.Min(valsLen, this._fields.Length);
                for (int i = 0; i < len; i++)
                {
                    string alias = this._fields[i];
                    IModelField field = m.GetFieldByAlias(alias);
                    if (field == null)
                        continue;
                    field.Set(vals[i]);
                }
                list.Add(m);
            }
            return list;
        }

        public Dictionary<string, object> ToDict(int index)
        {
            if (index < 0)
                throw new Exception("index不能小于0");
            if (index > this._values.Count - 1)
                throw new Exception("index超出范围");

            object[] vals = this._values[index];
            int valsLen = vals.Length;
            Dictionary<string, object> dict = new Dictionary<string, object>(valsLen);
            int len = Math.Min(valsLen, this._fields.Length);
            for (int i = 0; i < len; i++)
            {
                string alias = this._fields[i];
                dict[alias] = vals[i];
            }
            return dict;
        }

        public Dictionary<string, object> FirstToDict()
        {
            return this.ToDict(0);
        }

        public bool TryGetValue(int index, string paramName, out object val)
        {
            if (index < 0)
                throw new Exception("index不能小于0");
            if (index > this._values.Count - 1)
            {
                val = null;
                return false;
            }
            int i;
            if (!this._dictFieldIndex.TryGetValue(paramName, out i))
            {
                val = null;
                return false;
            }

            object[] arr = this._values[index];
            if (i <= arr.Length - 1)
            {
                val = arr[i];
                return true;
            }
            else
            {
                val = null;
                return true;
            }
        }

        public bool TryGetFirstString(string paramName, out string result)
        {
            return TryGetString(0, paramName, out result);
        }

        public bool TryGetString(int index, string paramName, out string result)
        {
            object val;
            if (!this.TryGetValue(index, paramName, out val))
            {
                result = null;
                return false;
            }
            else
            {
                result = Convert.ToString(val);
                return true;
            }
        }

        public bool TryGetFirstInt(string paramName, out int result)
        {
            return TryGetInt(0, paramName, out result);
        }

        public bool TryGetInt(int index, string paramName, out int result)
        {
            string str;
            if (!this.TryGetString(index, paramName, out str))
            {
                result = -1;
                return false;
            }
            else
            {
                if (!int.TryParse(str, out result))
                {
                    result = -1;
                    return false;
                }
                return true;
            }
        }

        public bool TryGetFirstLong(string paramName, out long result)
        {
            return TryGetLong(0, paramName, out result);
        }

        public bool TryGetLong(int index, string paramName, out long result)
        {
            string str;
            if (!this.TryGetString(index, paramName, out str))
            {
                result = -1;
                return false;
            }
            else
            {
                if (!long.TryParse(str, out result))
                {
                    result = -1;
                    return false;
                }
                return true;
            }
        }

        public bool TryGetFirstDecimal(string paramName, out decimal result)
        {
            return TryGetDecimal(0, paramName, out result);
        }

        public bool TryGetDecimal(int index, string paramName, out decimal result)
        {
            string str;
            if (!this.TryGetString(index, paramName, out str))
            {
                result = -1;
                return false;
            }
            else
            {
                if (!decimal.TryParse(str, out result))
                {
                    result = -1;
                    return false;
                }
                return true;
            }
        }

        public bool TryGetFirstDouble(string paramName, out double result)
        {
            return TryGetDouble(0, paramName, out result);
        }

        public bool TryGetDouble(int index, string paramName, out double result)
        {
            string str;
            if (!this.TryGetString(index, paramName, out str))
            {
                result = -1;
                return false;
            }
            else
            {
                if (!double.TryParse(str, out result))
                {
                    result = -1;
                    return false;
                }
                return true;
            }
        }

        public bool TryGetFirstBool(string paramName, out bool result)
        {
            return TryGetBool(0, paramName, out result);
        }

        public bool TryGetBool(int index, string paramName, out bool result)
        {
            string str;
            if (!this.TryGetString(index, paramName, out str))
            {
                result = false;
                return false;
            }
            else
            {
                if (!bool.TryParse(str, out result))
                {
                    result = false;
                    return false;
                }
                return true;
            }
        }

        public bool TryGetFirstDateTime(string paramName, out DateTime result)
        {
            return TryGetDateTime(0, paramName, out result);
        }

        public bool TryGetDateTime(int index, string paramName, out DateTime result)
        {
            string str;
            if (!this.TryGetString(index, paramName, out str))
            {
                result = DateTime.MinValue;
                return false;
            }
            else
            {
                if (!DateTime.TryParse(str, out result))
                {
                    result = DateTime.MinValue;
                    return false;
                }
                return true;
            }
        }

        internal void AddValues(object[] vals)
        {
            this._values.Add(vals);
        }

        internal void AddModel(IModel model)
        {
            object[] vals = new object[this._fields.Length];
            int i = 0;
            foreach (string f in this._fields)
            {
                IModelField field = model.GetFieldByAlias(f);
                if (field == null)
                    continue;
                if (field.Type == FieldType.IntList ||
                    field.Type == FieldType.LongList ||
                    field.Type == FieldType.StringList)
                {
                    vals[i] = field.ToString();
                }
                else
                    vals[i] = field.OValue;
                i++;
            }
            this._values.Add(vals);
        }

        internal void AddModelList(IList<IModel> list)
        {
            foreach (IModel model in list)
                this.AddModel(model);
        }

        public void WriteJson(JsonWriter jw)
        {
            jw.WriteStartObject(); ;
            if (!String.IsNullOrEmpty(this._name))
            {
                jw.WritePropertyName("n");
                jw.WriteValue(this._name);
            }
            jw.WritePropertyName("f");
            jw.WriteValue(ArrayUtil.Join(this._fields, ","));

            jw.WritePropertyName("v");
            jw.WriteStartArray();
            foreach (object[] vals in this._values)
            {
                jw.WriteStartArray();
                foreach (object val in vals)
                {
                    if (TypeUtil.IsDateTime(val))
                        jw.WriteValue(Convert.ToDateTime(val).ToString("yyyy-MM-dd HH:mm:ss"));
                    else
                        jw.WriteValue(val);
                }
                jw.WriteEndArray();
            }
            jw.WriteEndArray();

            jw.WriteEndObject();
        }
    }
}
